namespace ActiveRecord

import System

class Expression:
   [Property(Statement)]
   _statement as string
   def constructor():
      pass
   def constructor(val as string):
      _statement = val
   public override def ToString() as string:
      return "${_statement}"
#   public static def Create(val as string) as Expression:
#      return Expression(val)
#   public static def Equals(column as string, value) as string:
#      return "${column} = ${value}"

class KeyValueExpression(Expression):
   [Property(Value)]
   _value
   [Property(Key)]
   _key as string
   def constructor(key as string, value):
      _key = key
      _value = value
   public override def ToString() as string:
      return "${_key} = ${_value}"
   public static def Create(key as string, value) as Expression:
      return KeyValueExpression(key, value)

class WhereExpression(KeyValueExpression):
   def constructor(column as string, value):
      super(column, value)
#   public static def Create(column as string, value) as WhereExpression:
#      return WhereExpression(column, value)

class OrderByExpression(Expression):
   def constructor(val as string):
      super(val)
#   public static def Create(val as string) as OrderByExpression:
#      return OrderByExpression(val)

class GroupByExpression(Expression):
   def constructor(val as string):
      super(val)
#   public static def Create(val as string) as GroupByExpression:
#      return GroupByExpression(val)

class HavingExpression(KeyValueExpression):
   def constructor(column as string, value):
      super(column, value)
#   public static def Create(column as string, value) as HavingExpression:
#      return HavingExpression(column, value)
      
class JoinExpression(Expression):
   [Property(TableRHS)]
   _tableRHS as string
   [Property(KeyRHS)]
   _keyRHS as string
   [Property(TableLHS)]
   _tableLHS as string
   [Property(KeyLHS)]
   _keyLHS as string
   def constructor(tableLHS as string, keyLHS as string, tableRHS as string, keyRHS as string):
      _tableLHS = tableLHS
      _keyLHS = keyLHS
      _tableRHS = tableRHS
      _keyRHS = keyRHS
      super(self.ToString())
   public override def ToString() as string:
      return "join ${_tableLHS} on ${_tableLHS}.${_keyLHS} = ${_tableRHS}.${_keyRHS} "

# convenience class to make instantiating Expressions easier
static class SQL:
   public static def Where(column as string, value) as WhereExpression:
      return WhereExpression(column, value)
   public static def OrderBy(columns as string) as OrderByExpression:
      return OrderByExpression(columns)
   public static def Having(column as string, value) as HavingExpression:
      return HavingExpression(column, value)
   public static def GroupBy(columns as string) as GroupByExpression:
      return GroupByExpression(columns)
   public static def BuildWhereStmt(*wheres as (WhereExpression)) as string:
      return joinStatements("where", "and", *wheres)
   public static def BuildOrderByStmt(*orderBys as (OrderByExpression)) as string:
      return joinStatements("order by", ",", *orderBys)
   public static def BuildGroupByStmt(*groupBys as (GroupByExpression)) as string:
      return joinStatements("group by", "and", *groupBys)
   public static def BuildHavingStmt(*havings as (HavingExpression)) as string:
      return joinStatements("having", ",", *havings)   
   public static def BuildJoinStmt(*joins as (JoinExpression)) as string:
      return string.Join(" ",  array(expr.ToString() for expr in joins))
   private static def joinStatements(initialToken as string, joinToken as string, *expressions as (Expression)) as string:
      stmt = string.Join(" ${joinToken} ", array(expr.ToString() for expr in expressions))
      return " ${initialToken} ${stmt}"